﻿/****************************************************************************
Copyright (c) 2014-2015 凌惊雪 微信:Lingjingxue 邮箱:lingjingxue@sina.com QQ:271487457

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/

using log4net;
using UtilLib;
using System;
using System.Diagnostics;
using System.Reflection;
using System.Collections.Generic;
using System.Collections.Concurrent;
using UtilPublic.ServerLoger;
using System.Threading;
using System.Linq;

namespace UtilPublic.ApiDispatcher
{
    /// <summary>
    /// 属性字符串
    /// </summary>
    [AttributeUsage(AttributeTargets.Method)]
    public class ApiDpCmdAttribute : Attribute
    {
        /// <summary>
        /// 
        /// </summary>
        public string Cmd { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public string Desc { get; set; }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="cmd"></param>
        /// <param name="desc"></param>
        public ApiDpCmdAttribute(string cmd, string desc) { Cmd = cmd; Desc = desc; }
    }
    /// <summary>
    /// 
    /// </summary>
    public class ApiDpCmdAction
    {
        /// <summary>
        /// 
        /// </summary>
        public ApiDpCmdAttribute Att { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public Action<string, string[]> Act { get; set; }
    }
    /// <summary>
    /// 命令行指令
    /// </summary>
    public static class ApiDpCmdMgr
    {
        /// <summary>
        /// 指令列表
        /// </summary>
        public static Dictionary<string, ApiDpCmdAction> DictCmdApi = new Dictionary<string, ApiDpCmdAction>();
        /// <summary>
        /// 指令
        /// </summary>
        private class CmdInfo { public string Cmd; public string[] Args; }
        /// <summary>
        /// 指令队列
        /// </summary>
        private static ConcurrentQueue<CmdInfo> ListCmds = new ConcurrentQueue<CmdInfo>();
        /// <summary>
        /// 添加控制器
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        public static void AddController<T>(T t)
        {
            if (t == null)
            {
                return;
            }
            Type type = t.GetType();
            var methods = type.GetMethods();
            //loger.Warn($"AddController {methods.Length}");
            foreach (var method in methods)
            {
                var atts = method.GetCustomAttributes(typeof(ApiDpCmdAttribute), true);
                if (atts.Length > 0)
                {
                    var att = ((ApiDpCmdAttribute)atts[0]);
                    var api = new ApiDpCmdAction()
                    {
                        Att = att,
                        Act = (Action<string, string[]>)Delegate.CreateDelegate(typeof(Action<string, string[]>), t, method),
                    };
                    DictCmdApi[api.Att.Cmd] = api;
                }
            }
        }
        /// <summary>
        /// 启动指令线程
        /// </summary>
        public static void Start()
        {
            while (true)
            {
                string Cmd = Console.ReadLine();
                string[] args = Cmd.Split(UtilEnum.分隔符空格);
                if (args.Length > 0)
                {
                    ListCmds.Enqueue(new CmdInfo() { Cmd = args[0].ToLower(), Args = args });
                }
                Thread.Sleep(100);
            }
        }
        /// <summary>
        /// 指令器心跳
        /// </summary>
        public static void Loop()
        {
            while (ListCmds.TryDequeue(out var cmd))
            {
                ProcessCmds(cmd.Cmd, cmd.Args);
            }
        }
        /// <summary>
        /// 处理指令
        /// </summary>
        /// <param name="cmd"></param>
        /// <param name="args"></param>
        public static void ProcessCmds(string cmd, string[] args)
        {
            if (DictCmdApi.TryGetValue(cmd, out var api))
            {
                try
                {
                    api.Act(cmd, args);

                    #region 测试性能代码
                    //int length = 10000000;
                    //Stopwatch watch1 = Stopwatch.StartNew();
                    //for (var i = 0; i < length; i++)
                    //{
                    //    BaseCmdApiController.Instance.TestTest(cmd, args);
                    //}
                    //watch1.Stop();
                    //Console.WriteLine($"{watch1.Elapsed}");

                    //Stopwatch watch2 = Stopwatch.StartNew();
                    //for (var i = 0; i < length; i++)
                    //{
                    //    api.Method.Invoke(api.Obj, new object[] { cmd, args, });
                    //}
                    //watch2.Stop();
                    //Console.WriteLine($"{watch2.Elapsed}");
                    //Console.WriteLine($"{(double)(watch2.Elapsed.Ticks) / watch1.Elapsed.Ticks}");

                    //Stopwatch watch3 = Stopwatch.StartNew();
                    //for (var i = 0; i < length; i++)
                    //{
                    //    api.Act(cmd, args);
                    //}
                    //watch3.Stop();
                    //Console.WriteLine($"{watch3.Elapsed}");
                    //Console.WriteLine($"{(double)(watch3.Elapsed.Ticks) / watch1.Elapsed.Ticks}");
                    #endregion
                }
                catch (Exception e)
                {
                    loger.Warn($"处理指令：{cmd} {args.ToList().ToStr(" ")} 出错", e);
                }
            }
            else
            {
                loger.Warn($"无效指令：{cmd} {args.ToList().ToStr(" ")} 请输入 help 查看全部指令");
            }
        }
    }
}